/**
 * 
 */
package com.lorizz.picpub.services.impl;

import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.File;

import java.util.HashMap;
import java.util.Map;

import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.ImageProcessingException;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.MetadataException;
import com.drew.metadata.exif.ExifDirectory;
import com.lorizz.picpub.services.EXIF;
import com.lorizz.picpub.services.ImageService;
import com.lorizz.picpub.services.EXIF.DATATYPE;

/**
 * @author wind hong
 * 
 */
public class ImageServiceImpl implements ImageService {

    @Override
    public BufferedImage scale(BufferedImage image, int maxWidth, int maxHeigth) {
        int type = (image.getTransparency() == Transparency.OPAQUE) ? BufferedImage.TYPE_INT_RGB
                : BufferedImage.TYPE_INT_ARGB;
        BufferedImage ret = image;
        int w = image.getWidth();
        int h = image.getHeight();
        if (w <= maxWidth && h <= maxHeigth)
            return ret;

        int w2, h2;
        if ((w / maxWidth) > (h / maxHeigth)) {
            w2 = maxWidth;
            h2 = (int) ((float) h / ((float) w / (float) maxWidth));
        } else {
            w2 = (int) ((float) w / ((float) h / (float) maxHeigth));
            h2 = maxHeigth;
        }

        do {
            w /= 2;
            if (w < w2) {
                w = w2;
            }
            h /= 2;
            if (h < h2) {
                h = h2;
            }
            BufferedImage tmp = new BufferedImage(w, h, type);
            Graphics2D g2 = tmp.createGraphics();
            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
            g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            g2.drawImage(ret, 0, 0, w, h, null);
            g2.dispose();
            ret = tmp;
        } while (w != w2 || h != h2);

        return ret;
    }

    @Override
    public BufferedImage crop(BufferedImage image, int width, float percentage) {
        BufferedImage ret = image;
        int w = image.getWidth();
        int h = image.getHeight();
        if (w <= width && h <= width)
            return ret;

        if ((w / width) > (h / width)) {
            if ((float) width / h < percentage) {
                int h2 = (int) ((float) width / percentage);
                ret = scale(image, w, h2);
                w = ret.getWidth();
                h = ret.getHeight();
            }
        } else {
            if ((float) width / w < percentage) {
                int w2 = (int) ((float) width / percentage);
                ret = scale(image, w2, h);
                w = ret.getWidth();
                h = ret.getHeight();
            }
        }

        int x, y, w2, h2;
        x = (w <= width) ? 0 : (int) ((float) (w - width) / 2);
        y = (h <= width) ? 0 : (int) ((float) (h - width) / 2);
        w2 = (w <= width) ? w : width;
        h2 = (h <= width) ? h : width;

        ret = ret.getSubimage(x, y, w2, h2);

        return ret;
    }

    @Override
    public Map<String, Object> meta(File image) {
        Map<String, Object> metas = new HashMap<String, Object>();
        try {
            Metadata metadata = ImageMetadataReader.readMetadata(image);
            Directory dir = metadata.getDirectory(ExifDirectory.class);
            
            put(metas, EXIF.IMAGE_WIDTH, dir, ExifDirectory.TAG_EXIF_IMAGE_WIDTH, DATATYPE.INT);
            put(metas, EXIF.IMAGE_HEIGHT, dir, ExifDirectory.TAG_EXIF_IMAGE_HEIGHT, DATATYPE.INT);
            put(metas, EXIF.X_RESOLUTION, dir, ExifDirectory.TAG_X_RESOLUTION, DATATYPE.DESCRIPTION);
            put(metas, EXIF.Y_RESOLUTION, dir, ExifDirectory.TAG_Y_RESOLUTION, DATATYPE.DESCRIPTION);
            put(metas, EXIF.DATETIME, dir, ExifDirectory.TAG_DATETIME, DATATYPE.DATE);
            put(metas, EXIF.MAKE, dir, ExifDirectory.TAG_MAKE, DATATYPE.DESCRIPTION);
            put(metas, EXIF.MODEL, dir, ExifDirectory.TAG_MODEL, DATATYPE.DESCRIPTION);
            put(metas, EXIF.EXIF_VERSION, dir, ExifDirectory.TAG_EXIF_VERSION, DATATYPE.DESCRIPTION);
            put(metas, EXIF.FLASHPIX_VERSION, dir, ExifDirectory.TAG_FLASHPIX_VERSION, DATATYPE.DESCRIPTION);
            put(metas, EXIF.COLOR_SPACE, dir, ExifDirectory.TAG_COLOR_SPACE, DATATYPE.DESCRIPTION);
            put(metas, EXIF.DATETIME_ORIGINAL, dir, ExifDirectory.TAG_DATETIME_ORIGINAL, DATATYPE.DATE);
            put(metas, EXIF.DATETIME_DIDITIZED, dir, ExifDirectory.TAG_DATETIME_DIGITIZED, DATATYPE.DATE);
            put(metas, EXIF.EXPOSURE_TIME, dir, ExifDirectory.TAG_EXPOSURE_TIME, DATATYPE.DESCRIPTION);
            put(metas, EXIF.F_NUMBER, dir, ExifDirectory.TAG_FNUMBER, DATATYPE.DESCRIPTION);
            put(metas, EXIF.EXPOSURE_PROGRAM, dir, ExifDirectory.TAG_EXPOSURE_PROGRAM, DATATYPE.DESCRIPTION);
            put(metas, EXIF.ISO_SPEED_RATINGS, dir, ExifDirectory.TAG_ISO_EQUIVALENT, DATATYPE.DESCRIPTION);
            put(metas, EXIF.SHUTTER_SPEED, dir, ExifDirectory.TAG_SHUTTER_SPEED, DATATYPE.DESCRIPTION);
            put(metas, EXIF.APERTURE, dir, ExifDirectory.TAG_APERTURE, DATATYPE.DESCRIPTION);
            put(metas, EXIF.BRIGHTNESS, dir, ExifDirectory.TAG_BRIGHTNESS_VALUE, DATATYPE.DESCRIPTION);
            put(metas, EXIF.MAX_APERTURE, dir, ExifDirectory.TAG_MAX_APERTURE, DATATYPE.DESCRIPTION);
            put(metas, EXIF.METERING_MODE, dir, ExifDirectory.TAG_METERING_MODE, DATATYPE.DESCRIPTION);
            put(metas, EXIF.FLASH, dir, ExifDirectory.TAG_FLASH, DATATYPE.DESCRIPTION);
            put(metas, EXIF.FOCAL_LENGTH, dir, ExifDirectory.TAG_FOCAL_LENGTH, DATATYPE.DESCRIPTION);
            put(metas, EXIF.FOCAL_LENGTH_35MM, dir, ExifDirectory.TAG_35MM_FILM_EQUIV_FOCAL_LENGTH, DATATYPE.DESCRIPTION);
            put(metas, EXIF.EXPOSURE_INDEX, dir, ExifDirectory.TAG_EXPOSURE_INDEX, DATATYPE.DESCRIPTION);
            put(metas, EXIF.EXPOSURE_MODE, dir, ExifDirectory.TAG_EXPOSURE_MODE, DATATYPE.DESCRIPTION);
            put(metas, EXIF.WHITE_BALANCE, dir, ExifDirectory.TAG_WHITE_BALANCE, DATATYPE.DESCRIPTION);
            put(metas, EXIF.WHITE_BALANCE_MODE, dir, ExifDirectory.TAG_WHITE_BALANCE_MODE, DATATYPE.DESCRIPTION);
            put(metas, EXIF.CONTRAST, dir, ExifDirectory.TAG_CONTRAST, DATATYPE.DESCRIPTION);
            put(metas, EXIF.SATURATION, dir, ExifDirectory.TAG_SATURATION, DATATYPE.DESCRIPTION);
            put(metas, EXIF.SHARPNESS, dir, ExifDirectory.TAG_SHARPNESS, DATATYPE.DESCRIPTION);
            
        } catch (ImageProcessingException e) {
        } 
        return metas;
    }
    
    
    
    private void put(Map<String, Object> metas, String key, Directory directory, int tagType, DATATYPE dataType) {
    	if (!directory.containsTag(tagType))
    		return;
    	try {
    		switch(dataType) {
    		case INT:
    			metas.put(key, directory.getInt(tagType));
    			break;
    		case STRING:
    			metas.put(key, directory.getString(tagType));
    			break;
    		case DATE:
    			metas.put(key, directory.getDate(tagType));
    			break;
    		default:
    			metas.put(key, directory.getDescription(tagType));
    		}
    	}catch (MetadataException e) {
    		e.printStackTrace();
		}
	}
    
    
    public static void main(String[] args) throws Exception {
    	File image = new File("C:\\Users\\xzhihon\\Pictures\\775960260_MAmz4-O.jpg");
    	Metadata metadata = ImageMetadataReader.readMetadata(image);
    	Directory directory = metadata.getDirectory(ExifDirectory.class);
    	
    	//TIFF
    	//A. Tags relating to image data structure
    	System.out.println("image width:" + directory.getInt(ExifDirectory.TAG_EXIF_IMAGE_WIDTH));
    	System.out.println("image height:" + directory.getInt(ExifDirectory.TAG_EXIF_IMAGE_HEIGHT));
    	System.out.println("x resolution:" + directory.getDescription(ExifDirectory.TAG_X_RESOLUTION));
    	System.out.println("y resolution:" + directory.getDescription(ExifDirectory.TAG_Y_RESOLUTION));
    	//B. Tags relating to recording offset
    	//C. Tags Relating to Image Data Characteristics
    	//D. Other Tags
    	System.out.println("date time:" + directory.getDate(ExifDirectory.TAG_DATETIME));
    	System.out.println("make:" + directory.getString(ExifDirectory.TAG_MAKE));
    	System.out.println("model:" + directory.getString(ExifDirectory.TAG_MODEL));
    	
    	//EXIF IFD
    	//A. Tags Relating to Version
    	System.out.println("exif version:" + directory.getDescription(ExifDirectory.TAG_EXIF_VERSION));
    	System.out.println("flashpix verison:" + directory.getDescription(ExifDirectory.TAG_FLASHPIX_VERSION));
    	//B. Tag Relating to Color Space
    	System.out.println("color space:" + directory.getDescription(ExifDirectory.TAG_COLOR_SPACE));
    	//C. Tags Relating to Image Configuration
    	//D. Tags Relating to User Information
    	//E. Tag Relating to Related File
    	//F. Tags Relating to Date and Time
    	System.out.println("date time original:" + directory.getDate(ExifDirectory.TAG_DATETIME_ORIGINAL));
    	System.out.println("date time digitized:" + directory.getDate(ExifDirectory.TAG_DATETIME_DIGITIZED));
    	//G. Tags Relating to Picture-Taking Conditions
    	System.out.println("exposure time:" + directory.getDescription(ExifDirectory.TAG_EXPOSURE_TIME));
    	System.out.println("f number:" + directory.getDescription(ExifDirectory.TAG_FNUMBER));
    	System.out.println("exposure program:" + directory.getDescription(ExifDirectory.TAG_EXPOSURE_PROGRAM));
    	System.out.println("ISO speed ratings:" + directory.getDescription(ExifDirectory.TAG_ISO_EQUIVALENT));
    	System.out.println("shutter speed value:" + directory.getDescription(ExifDirectory.TAG_SHUTTER_SPEED));
    	System.out.println("aperture value:" + directory.getDescription(ExifDirectory.TAG_APERTURE));
    	System.out.println("brightness value:" + directory.getDescription(ExifDirectory.TAG_BRIGHTNESS_VALUE));
    	System.out.println("max aperture value:" + directory.getDescription(ExifDirectory.TAG_MAX_APERTURE));
    	System.out.println("metering mode:" + directory.getDescription(ExifDirectory.TAG_METERING_MODE));
    	System.out.println("flash:" + directory.getDescription(ExifDirectory.TAG_FLASH));
    	System.out.println("focal length:" + directory.getDescription(ExifDirectory.TAG_FOCAL_LENGTH));
    	System.out.println("35mm focal length:" + directory.getDescription(ExifDirectory.TAG_35MM_FILM_EQUIV_FOCAL_LENGTH));
    	System.out.println("exposure index:" + directory.getDescription(ExifDirectory.TAG_EXPOSURE_INDEX));
    	System.out.println("exposure mode:" + directory.getDescription(ExifDirectory.TAG_EXPOSURE_MODE));
    	System.out.println("white balance:" + directory.getDescription(ExifDirectory.TAG_WHITE_BALANCE));
    	System.out.println("white balance mode:" + directory.getDescription(ExifDirectory.TAG_WHITE_BALANCE_MODE));
    	System.out.println("contrast:" + directory.getDescription(ExifDirectory.TAG_CONTRAST));
    	System.out.println("saturation:" + directory.getDescription(ExifDirectory.TAG_SATURATION));
    	System.out.println("sharpness:" + directory.getDescription(ExifDirectory.TAG_SHARPNESS));
    	
    }

}
